package com.bgi.pgdp.rest;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSONObject;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Controller
public class IndexRest {
	@Value("${app.authorizeUrl}")
	private String authorizeUrl;

	@Value("${app.clientUrl}")
	private String clientUrl;

	@Value("${app.resourceUrl}")
	private String resourceUrl;

	@Value(value = "${app.clientId}")
	private String clientId;

	@Value(value = "${app.clientSecret}")
	private String clientSecret;

	@Value("${server.port}")
	private String port;

	/**
	 * 应用首页
	 * @param response
	 * @throws IOException
	 */
	@RequestMapping("/app")
	private void app(HttpServletResponse response) throws IOException {
		response.sendRedirect(authorizeUrl + "/oauth/authorize?client_id=" + clientId + "&redirect_uri=" + clientUrl
				+ "/callback&response_type=code");
	}

	/**
	 * 应用回调页面
	 * @param code
	 * @param model
	 * @return
	 */
	@GetMapping("/callback")
	public String callback(@RequestParam String code, Model model) {
		String accessToken = getAccessToken(clientId, clientSecret, code);
		Map multiOmicsMap = getMultiOmics(accessToken);
		Map geneMap = getGene(accessToken);
		LinkedHashMap<String, String> reportMap = new LinkedHashMap<>();
		reportMap = getReportMap(multiOmicsMap, geneMap);
		model.addAttribute("reportMap", reportMap);
		
		return "app";
	}
	
	/**
	 * 写入数据
	 * @param writeInfo
	 * @return
	 */
	@RequestMapping("/writeData")
	@ResponseBody
	public Map writeData(@RequestBody DataWriteInfo writeInfo) {
		HashMap<String, Object> param = new HashMap<>();
		DataWriteInfo info = new DataWriteInfo();
		List<DataWriteInfo> datas = new ArrayList<>();
		info.dataElementId = "1";
		info.dataValue = writeInfo.height;
		datas.add(info);
		info = new DataWriteInfo();
		info.dataElementId = "2";
		info.dataValue = writeInfo.weight;
		datas.add(info);
		param.put("datas", datas);
		String url = resourceUrl + "/multiOmics/v1/writeData";
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		headers.add("Authorization", getAccessToken(clientId, clientSecret, null));
		HttpEntity<String> formEntity = new HttpEntity<String>(JSONObject.toJSONString(param), headers);
		RestTemplate restTemplate = new RestTemplate();
		return restTemplate.postForObject(url, formEntity, Map.class);
	}
	
	/**
	 * 获取示例报告
	 * @param apiRes
	 * @param geneMap
	 * @return
	 */
	private LinkedHashMap<String, String> getReportMap(Map apiRes, Map geneMap) {
		LinkedHashMap<String, String> result = new LinkedHashMap<>();
		Map<String, String> geneTypeMap = new HashMap<>();
		if (geneMap != null && geneMap.get("code").equals("0")) {
			List<Map> list = (List<Map>) geneMap.get("datas");
			for (Map map : list) {
				geneTypeMap.put((String) map.get("rsid"), (String) map.get("geneType"));
			}
		}
		// 先天体质检测
		String type = geneTypeMap.get("rs1421085").replaceAll("/", "");
		float bmi = 19.5f;// TODO
		if (type.equals("CC") || type.equals("CT") || type.equals("TC")) {
			if (bmi >= 18.5 && bmi <= 24) {
				result.put("先天体质检测", "易胖体质，日常摄入的过多热量更易转化为白色脂\r\n" + "肪组织，且难以被消耗。\r\n" + "但您看起来保持得不错，要坚持，不然容易反弹喔。");
			} else if (bmi > 24 && bmi <= 28) {
				result.put("先天体质检测", "易胖体质，日常摄入的过多热量更易转化为白色脂\r\n" + "肪组织，且难以被消耗。\r\n" + "目前您超重了，多动少吃，注意控制。");
			} else if (bmi > 28) {
				result.put("先天体质检测", "易胖体质，日常摄入的过多热量更易转化为白色脂\r\n" + "肪组织，且难以被消耗。\r\n" + "不要放弃，管住嘴迈开腿，与胖基因斗争到底！");
			} else if (bmi < 18.5) {
				result.put("先天体质检测", "易胖体质，日常摄入的过多热量更易转化为白色脂\r\n" + "肪组织，且难以被消耗。\r\n" + "可您却那么瘦，别过度减肥，健康最美。");
			}
		} else if (type.equals("TT")) {
			if (bmi >= 18.5 && bmi <= 24) {
				result.put("先天体质检测", "不易胖体质，体内脂肪更容易燃烧、消耗，多运动能保持好身材。\r\n" + "您看起来保持得不错，要坚持下去。");
			} else if (bmi > 24 && bmi <= 28) {
				result.put("先天体质检测", "不易胖体质，体内脂肪更容易燃烧、消耗，多运动能保持好身材。\r\n" + "但您还是超重了，多动少吃，注意控制。");
			} else if (bmi > 28) {
				result.put("先天体质检测", "不易胖体质，体内脂肪更容易燃烧、消耗，多运动能保持好身材。\r\n" + "可您却如此放纵，管住嘴迈开腿，别浪费了这天赋。");
			} else if (bmi < 18.5) {
				result.put("先天体质检测", "不易胖体质，体内脂肪更容易燃烧、消耗，多运动能保持好身材。\r\n" + "您那么瘦，别过度减肥，健康最美。");
			}
		}
		// 减肥方式建议
		type = geneTypeMap.get("rs662799").replaceAll("/", "");
		if (type.equals("GG") || type.equals("GA") || type.equals("AG")) {
			result.put("减肥方式建议", "加强运动减肥可能对您效果更大。\r\n" + "建议可以通过适当加强运动量的方式来进行控制体重。");
		} else if (type.equals("AA")) {
			result.put("减肥方式建议", "控制饮食减肥可能对您效果更大。\r\n" + "建议尽量避免高脂肪、高热量食物，少食多餐。");
		}
		// 血糖调节能力
		type = geneTypeMap.get("rs7903146").replaceAll("/", "");
		int fbgFlag = 0; // TODO
		if (type.equals("CC")) {
			if (fbgFlag == -1) {
				result.put("血糖调节能力", "血糖调节能力强。\r\n" + "但您近期的空腹血糖过低，日常饮食可适量进食多些高热量、高碳水化合物食物喔。");
			} else if (fbgFlag == 0) {
				result.put("血糖调节能力", "血糖调节能力强。\r\n" + "不用特别注意碳水化合物、脂肪的饮食结构，但也要注意健康饮食喔。");
			} else if (fbgFlag == 1) {
				result.put("血糖调节能力", "血糖调节能力强。\r\n" + "但您近期的空腹血糖过高，日常饮食应避免过量进食高热量、高碳水化合物食物喔。");
			}
		} else if (type.equals("CT") || type.equals("TC")) {
			if (fbgFlag == -1) {
				result.put("血糖调节能力", "血糖调节能力中。\r\n" + "但您近期的空腹血糖过低，日常饮食可适量进食高热量、高碳水化合物食物喔，但也别过度过量。");
			} else if (fbgFlag == 0) {
				result.put("血糖调节能力", "血糖调节能力中。\r\n" + "日常饮食应避免过量进食高热量、高碳水化合物食物喔。");
			} else if (fbgFlag == 1) {
				result.put("血糖调节能力", "血糖调节能力中。\r\n" + "您近期的空腹血糖过高，日常饮食应避免过量进食高热量、高碳水化合物食物喔。");
			}
		} else if (type.equals("TT")) {
			if (fbgFlag == -1) {
				result.put("血糖调节能力", "血糖调节能力弱。\r\n" + "但您近期的空腹血糖过低，日常饮食可适量进食高热量、高碳水化合物食物喔，但也别过度过量。");
			} else if (fbgFlag == 0) {
				result.put("血糖调节能力", "血糖调节能力弱。\r\n" + "日常饮食应注意采用低热量－低碳水化合物食物组合（少吃米饭和面条，不吃肥肉等）。");
			} else if (fbgFlag == 1) {
				result.put("血糖调节能力", "血糖调节能力弱。\r\n" + "您近期的空腹血糖也偏高，日常饮食应注意采用低热量－低碳水化合物食物组合（少吃米饭和面条，不吃肥肉等）。");
			}
		}
		// 血脂代谢能力
		type = geneTypeMap.get("rs1801282").replaceAll("/", "");
		int lmaFlag = 0;// TODO
		if (type.equals("GG") || type.equals("CG") || type.equals("GC")) {
			if (fbgFlag == 1) {
				result.put("血脂代谢能力", "血脂代谢能力弱。\r\n" + "您近期的血脂偏高，日常饮食中应多吃单不饱和脂肪酸食物（鱼油、橄榄油等），减少食用高脂肪食物。");
			} else if (fbgFlag == 0) {
				result.put("血脂代谢能力", "血脂代谢能力弱。\r\n" + "日常饮食中应多吃单不饱和脂肪酸食物（鱼油、橄榄油等），减少食用高脂肪食物。");
			}
		} else if (type.equals("CC")) {
			if (fbgFlag == 1) {
				result.put("血脂代谢能力", "血脂代谢能力强。\r\n" + "但您近期的血脂偏高，日常饮食中应多吃单不饱和脂肪酸食物（鱼油、橄榄油等），减少食用高脂肪食物。");
			} else if (fbgFlag == 0) {
				result.put("血脂代谢能力", "血脂代谢能力强。\r\n" + "日常饮食中可正常进食脂肪类食物（如鸡牛羊鱼肉等），但也不能过量喔。");
			}
		}

		return result;
	}

	/**
	 * 获取多组学数据
	 * @param accessToken
	 * @return
	 */
	private Map getMultiOmics(String accessToken) {
		String url = resourceUrl + "/multiOmics/v1/readData/";
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		headers.add("Authorization", accessToken);
		HttpEntity<String> formEntity = new HttpEntity<String>(JSONObject.toJSONString(null), headers);
		RestTemplate restTemplate = new RestTemplate();
		return restTemplate.postForObject(url, formEntity, Map.class);
	}

	/**
	 * 获取基因数据
	 * @param accessToken
	 * @return
	 */
	private Map getGene(String accessToken) {
		String url = resourceUrl + "/common/v1/variant/rsid";
		String paramStr = "{\r\n" + "	\"rsids\": [\r\n" + "		\"rs1421085\",\r\n" + "		\"rs662799 \",\r\n"
				+ "		\"rs7903146\",\r\n" + "		\"rs1801282\"\r\n" + "	  ],\r\n"
				+ "	\"sampleId\":\"1900581082C\",\r\n" + "	\"fieldRange\":\"basic\"\r\n" + "}";
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		headers.add("Authorization", accessToken);
		HttpEntity<String> formEntity = new HttpEntity<String>(paramStr, headers);
		RestTemplate restTemplate = new RestTemplate();
		return restTemplate.postForObject(url, formEntity, Map.class);
	}

	/**
	 * 获取accessToken
	 * @param clientId
	 * @param clientSecret
	 * @param code
	 * @return
	 */
	private String getAccessToken(String clientId, String clientSecret, String code) {
		String accessToken = "";
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
				.getRequest();
		HttpSession httpSession = request.getSession();
		accessToken = httpSession.getAttribute("accessToken") == null ? ""
				: httpSession.getAttribute("accessToken").toString();
		if (!StringUtils.isEmpty(accessToken)) {
			return accessToken;
		}
		String url = authorizeUrl + "/oauth/token";
		MultiValueMap<String, String> paramMap = new LinkedMultiValueMap<String, String>();
		paramMap.add("grant_type", "authorization_code");
		paramMap.add("code", code);
		paramMap.add("redirect_uri", clientUrl + "/callback");
		paramMap.add("client_id", clientId);
		paramMap.add("client_secret", clientSecret);
		RestTemplate restTemplate = new RestTemplate();
		HashMap jsonObj = restTemplate.postForObject(url, paramMap, HashMap.class);
		if (jsonObj != null) {
			accessToken = jsonObj.get("token_type") + " " + jsonObj.get("access_token");
			httpSession.setAttribute("accessToken", accessToken);
		}
		return accessToken;
	}

}
